/*
* BudoDubboHttpApiJavascriptSdk
*/

(function() {
    "use strict";

    var log = console || { warn : function () {} }; 

    // 列出所有接口和接口的方法
    var _apiMetas = [
        {"type": "DataMessageApi","methods": ["post"]},
        {"type": "DataNodeApi","methods": ["list", "listNameByIds", "findById", "showGrants", "insertIgnoreNull", "updateIgnoreNull", "checkDataNode"]},
        {"type": "DataProducerApi","methods": ["loadDataProducer", "restartThread"]},
        {"type": "EntryBufferApi","methods": ["list"]},
        {"type": "FieldMappingApi","methods": ["list", "listByPipelineId", "listCountByPipelineIds", "findById"]},
        {"type": "LogPositionApi","methods": ["deleteLogPosition", "showBinaryLogs", "listLogPosition"]},
        {"type": "PipelineApi","methods": ["list", "findById", "insertIgnoreNull", "updateIgnoreNull"]},
        {"type": "AccessLogApi","methods": ["list"]}
    ]; 

    // 类 BudoDubboHttpApiJavascriptSdk
    var BudoDubboHttpApiJavascriptSdk = function() {
        var _sdk = this;

        // 属性默认值
        _sdk._url = location ? location.pathname: null;

        _sdk._timeout = 25 * 1000; // 请求超时默认25秒

        _sdk._transporter = JQueryTransporter;

        _sdk._responseHandler = ResponseHandler;

        _sdk._serialization = new JsonSerialization();

        // 默认的 DeferredFactory
        _sdk._deferredFactory = function(_request, _sdk) {
            return new Deferred(_request, _sdk);
        };

        // 默认回调
        _sdk._callback = {
            "success": function() { 
                log.warn("default _sdk._callback success : arguments=" + JSON.stringify(arguments)); 
            },
            "fail": function() { 
                log.warn("default _sdk._callback fail : arguments=" + JSON.stringify(arguments)); 
            }
        };

        _sdk.setCallback = function(callback) {
            if ( !!!callback || !!!callback.success || !!!callback.fail || typeof callback.success != "function" || typeof callback.fail != "function" ) {
                throw "sdk.setCallback must input a object like {success:function, fail:function}";
            }

            _sdk._callback = callback;
        };

        _sdk.setTransporter = function(transporter) {
            if (typeof transporter != "function") { // 传入function
                throw "sdk.setTransporter must input a function";
            }

            _sdk._transporter = transporter;
        };

        _sdk.setResponseHandler = function(responseHandler) {
            if (typeof responseHandler != "function") { // 传入function
                throw "sdk.setResponseHandler must input a function";
            }

            _sdk._responseHandler = responseHandler;
        };

        // 属性Setter
        _sdk.setDeferredFactory = function(deferredFactory) {
            _sdk._deferredFactory = deferredFactory;
        };

        // 属性Setter
        _sdk.setTimeout = function(timeout) {
            _sdk._timeout = timeout;
        };

        _sdk.setRequestFilter = function(requestFilter) {
            _sdk._requestFilter = requestFilter;
        };

        _sdk.setUrl = function(url) {
            _sdk._url = url;
        };

        _sdk.setSerialization = function(serialization) {
            _sdk._serialization = serialization;
        };

        // 每一个接口
        _apiMetas.forEach(function(_apiMeta) {
            _sdk[_apiMeta.type] = function() {
                var _interfaceDelegateCacheFieldName = "_InterfaceDelegate_" + _apiMeta.type;
                if ( !!! _sdk[_interfaceDelegateCacheFieldName]) { // 缓存
                    _sdk[_interfaceDelegateCacheFieldName] = new InterfaceDelegate(_sdk, _apiMeta.type, _apiMeta.methods);
                }
                return _sdk[_interfaceDelegateCacheFieldName]; 
            };
        });
    };
    // end BudoDubboHttpApiJavascriptSdk


    // 类 InterfaceDelegate, 对应一个Java Interface
    var InterfaceDelegate = function (_sdk, _interfaceName, _methodNames) {
        var _interfaceDelegate = this;

        _methodNames.forEach(function(_methodName) {

            // 添加代理方法
            _interfaceDelegate[_methodName] = function() {
                var _methodArgs = Array.prototype.slice.apply(arguments);

                // 构造 _request 对象
                var _request = {
                    "interfaceName": _interfaceName,
                    "methodName": _methodName,
                    "args": _methodArgs
                };

                return _sdk._deferredFactory(_request, _sdk); // 返回Deferred以传入回调
            };
        });
    }


    // 类 JsonSerialization , 序列化
    var JsonSerialization = function() {
        // obj to str
        this.serialize = function(_obj) {
            return JSON.stringify(_obj);
        };

        // str to obj
        this.deserialize = function(_str) {
            try {
                return typeof _str === "object" ? _str : JSON.parse(_str);
            } catch ( e ) {
                log.warn("#149 deserialize error, _str=" + _str + ", e=" + e, e);
                return { result : { error_description : 'deserialize error ' + _str } };
            }
        };
    };


    // 类 Deferred, 请求回调
    var Deferred = function (_request, _sdk) {
        var _deferred = this;

        // 传入回调，异步执行请求，支持传入两个 function 作为 两个回调 
        _deferred.then = function() {
            var _callbacks = Array.prototype.slice.apply(arguments);

            try {
                _request.async = true; // 异步执行

                var _preparedRequest = _prepareRequest(_sdk, _request, _callbacks);
                _sdk._transporter(_preparedRequest); // 发起通信请求
            } catch(_error) {
                _request.error = _error;
                _sdk._responseHandler(_request);
            }

            return _deferred;
        }

        // 请求同步执行，返回结果
        _deferred.result = function() {
            _request.async = false; // 同步执行

            var _preparedRequest = _prepareRequest(_sdk, _request, null);
            var _responseText = _sdk._transporter(_preparedRequest); // 发起请求
            return _sdk._serialization.deserialize(_responseText); // 结果反序列化
        }

        // 私有方法 构造 _request 对象
        var _prepareRequest = function(_sdk, _request, _callbacks) {
            var _mergedCallback = {};

            if ( !! _callbacks && !! _callbacks[0] ) {
                if (typeof _callbacks[0] === "function") { // 传入一个或两个function作为回调
                    _mergedCallback.success = _callbacks[0]; // 第一个参数是成功回调
                    _mergedCallback.fail = _callbacks[1] || _sdk._callback.fail; // 第二个参数是失败回调，没有就走默认失败回调
                } else { // 传入一个 object 作为回调
                    _mergedCallback.success = _callbacks[0].success || _sdk._callback.success; // 取对象中的对应回调，没有就取默认回调
                    _mergedCallback.fail = _callbacks[0].fail || _sdk._callback.fail;
                }
            } else {
                _mergedCallback = _sdk._callback;
            }

            _request.callback = _mergedCallback;

            _request.requestBody = _sdk._serialization.serialize(_request.args[0] || {}); // 无参数时传空对象

            _request.responseHandler = _sdk._responseHandler;
            _request.serialization = _sdk._serialization;
            _request.headers={};
            _request.parameters={};
            _request.timeout=_sdk._timeout;
            _request.url=_sdk._url;

            // 执行 requestFilter
            if (_sdk._requestFilter) {
                _request = _sdk._requestFilter(_request);
            }

            return _request;
        }
    }


    // JQueryTransporter 通信层
    var JQueryTransporter = function(_request) {
        var _ajax_url = _request.url + "/" + _request.interfaceName + "." + _request.methodName + "?" + $.param(_request.parameters);

        var _ajax = $.ajax({
            method: "POST",
            contentType: "application/json",
            url: _ajax_url,
            timeout : _request.timeout, 
            data: _request.requestBody,
            async: _request.async,
            headers: _request.headers
        });

        if (_request.async) { // 异步
            _ajax.done(function(_responseBody, _textStatus, jqXHR) {
                _request.responseBody = _responseBody;
                _request.responseHandler(_request)
            }).fail(function(jqXHR, _textStatus, _error) {
                _request.responseBody = jqXHR.responseText;
                _request.error = _request.serialization.deserialize(jqXHR.responseText).result;
                _request.responseHandler(_request)
            });
        } else { // 同步请求不支持 timeout
            return _ajax.responseText;
        }
    };

    // ResponseHandler 返回结果处理
    var ResponseHandler = function(_request) {
        if ( !!_request.error ) {
            _request.callback.fail(_request.error, _request);
        } else {
            var _responseBody = _request.responseBody;
            var _responseEntity =  _request.serialization.deserialize(_responseBody); // 结果反序列化
            _request.callback.success(_responseEntity, _request);
        }
    };

    // 挂载根对象
    var _root = null;

    if (!!window) {
        _root = window; // 浏览器环境, 挂载到window
    } else if (!!wx) {
        _root = wx; // 微信小程序, 挂载到wx
    } else {
        throw "window or wx not found, contact the developer now";
    }

    _root.BudoDubboHttpApiJavascriptSdk = BudoDubboHttpApiJavascriptSdk;

    _root.JQueryTransporter = JQueryTransporter;

    _root.JsonSerialization = JsonSerialization;

    _root.ResponseHandler = ResponseHandler;
})();